/*
 * FloorProxy.cpp
 *
 *  Created on: 22/04/2012
 *      Author: alex
 */

#include "FloorProxy.h"

#include <stdlib.h>
#include <sys/types.h>
#include <signal.h>
#include <sys/wait.h>
#include <sstream>

#include "../common/Argv.h"

using namespace std;

FloorProxy::FloorProxy(int floorAmmount,std::string keyGeneratorPath, std::string baseFileName):m_IsRunning(true)
{
	m_BaseFileName = baseFileName;
	m_FloorAmmount = floorAmmount;
	m_didStartProcesses = false;
	m_keyGeneratorPath = keyGeneratorPath;
}

FloorProxy::~FloorProxy()
{
}

void FloorProxy::start(bool startProcesses)
{
    int i;

    pid_t pid;
    m_PidVector.resize(m_FloorAmmount);

    PassengerQueue *floorQueue;
    stringstream floorQueueName;
    string floorExecFileName = "./floor";
    m_didStartProcesses = startProcesses;

    for(i=0; i< m_FloorAmmount; i++)
    {
    	//Defino el nombre del archivo a usar para el canal de
    	//comunicacion
    	floorQueueName.str("");
    	floorQueueName << m_BaseFileName << i;

    	//Creo la queue del lado del consumidor
    	floorQueue = new PassengerQueue(floorQueueName.str(),m_keyGeneratorPath,i,PassengerQueue::CONSUMER_END);

        if(startProcesses)
        {
        	//Creo la queue antes de forkear
        	floorQueue->create();

			//Creo un nuevo proceso
			pid = fork();

			if(pid == -1)
				throw new std::exception();

			//Si es el proceso padre
			if(pid != 0)
			{
				//Registro el canal de comunicacion del hijo y
				//su pid
				m_PidVector[i] = pid;
			}
			else
			{
				stringstream programArgs;

				//Llamo al codigo del hijo
				Argv argv;

				programArgs << floorExecFileName << " "<< floorQueueName.str() << " "
							<< i<< " "<< m_FloorAmmount<< " "<< m_keyGeneratorPath;

//	            cout << "ARGS"<< programArgs.str()<<".----" <<endl;
				argv.setSerializedArgs(programArgs.str());

				if(execv(floorExecFileName.c_str(), argv.getArgv())<0)
				{
					cout << "Error while launching the floor"<<endl;
					exit(1);
				}
			}
        }

    	floorQueue->open();
    	m_PassengerQueue[i] = floorQueue;
    }
}

void FloorProxy::stopGeneratingPassengers()
{
    int i;
    int processAmmount = m_PidVector.size();

    if(m_didStartProcesses)
        for(i=0;i < processAmmount ;i++)
            kill(m_PidVector[i], SIGUSR1);

}

void FloorProxy::stop()
{
    int i;
    int processAmmount = m_PassengerQueue.size();

    QueueVector::iterator it;

    for(i=0, it=m_PassengerQueue.begin();
    		i < processAmmount && it != m_PassengerQueue.end() ;
    		i++, it++)
    {
    	it->second->close();

    	if(m_didStartProcesses)
    	{
			kill(m_PidVector[i], SIGINT);
			waitpid(m_PidVector[i],NULL,0);
			it->second->destroy();
    	}
    	delete it->second;

    }

    m_PassengerQueue.clear();
    m_PidVector.clear();

	m_IsRunning = false;
}

int FloorProxy::getFloorAmmount()
{
	return m_FloorAmmount;
}

FloorIdentifierList FloorProxy::getWaitingFloors()
{
	QueueVector::iterator it;
	FloorIdentifierList waitingFloors;

	for(it=m_PassengerQueue.begin(); it!= m_PassengerQueue.end(); it++)
	{
		if(it->second->hasPassengers())
			waitingFloors.push_back(it->first);
	}

	return waitingFloors;
}

ElevatorPassenger *FloorProxy::getPassenger(FloorIdentifier floorId)
{
	return m_PassengerQueue[floorId]->popPassenger();
}

ElevatorPassenger *FloorProxy::peekPassenger(FloorIdentifier floorId)
{
	ElevatorPassenger *passenger = NULL;

	if(m_PassengerQueue[floorId]->hasPassengers())
		passenger = m_PassengerQueue[floorId]->peekPassenger();

	return passenger;
}

void FloorProxy::deletePeekedPassenger(FloorIdentifier floorId)
{
	m_PassengerQueue[floorId]->deletePeekedPassenger();
}

bool FloorProxy::hasPassengers(FloorIdentifier floorId)
{
	return m_PassengerQueue[floorId]->hasPassengers();
}

bool FloorProxy::isRunning()
{
	return m_IsRunning;
}
